package master;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.*;

/**
 * An override of JPanel for displaying complex numbers. You should never really have to create one of
 * these directly, instead try calling 'display' on a complex number
 * @author Luke Dobinson
 *
 */

public class ComplexNumberPanel extends JPanel implements MouseMotionListener,MouseListener,ActionListener{
	
	Component parent;
	ComplexNumber myN;
	float scale = 100f;//multipler to convert real coords to pixels

	int mouseX, mouseY;
	float savedScale;
	
	public static Timer refreshTimer = new Timer(25,null);
	
	boolean editable = true;
	
	static boolean antialiased = true;
	
	static Color lineColor = Color.gray;
	static Color vectorColor = Color.green;
	static Color stringColor = Color.white;
	static Color borderColor = Color.LIGHT_GRAY;
	static Color backgroundColor = new Color(50,50,50);
	
	/**
	 * Convert real coordinates to drawable pixel coordinates in the form of an array length 2
	 * @param xy = float[]{ real xCoordinate , real yCoordinate}
	 * @return
	 */
	protected int [] realToPix(float ... xy){
		if(xy.length!=2) throw new IllegalArgumentException("Invalid Coords");
		return new int[]{
				(int)(   scale*(float)(  (int)(xy[0])- this.getWidth()/2  )    ),
				(int)(   scale*(float)(  this.getHeight()/2 - (int)(xy[1])  )    )
				};
	}
	
	
	/**
	 * take pixel coordinates and convert them to the corresponding real coordinates
	 * @param xy
	 * @return
	 */
	protected float [] pixToReal(int ... xy){
		if(xy.length!=2) throw new IllegalArgumentException("Invalid Coords");
		return new float[]{
				(xy[0] - (float)(this.getWidth()/2))/scale,
				( (float)(this.getHeight()/2) - xy[1])/scale
		};
	}
	
	/**
	 * Constructor
	 * @param parent
	 * @param myN - the number to display
	 * @param scale - the scale of the number
	 * @param editable - should the number be alterable by the user
	 */
	public ComplexNumberPanel( Component parent, ComplexNumber myN , float scale, boolean editable){
		this.editable = editable;
		this.parent = parent;
		refreshTimer.addActionListener(this);
		this.setBackground(backgroundColor);
		this.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED, borderColor, backgroundColor));
		this.myN = myN;
		this.scale = scale;
		this.addMouseMotionListener(this);
		this.addMouseListener(this);
	}
	
	/**
	 * Starts the animated update timer
	 */
	public static void startAnimation(){
		refreshTimer.start();
	}
	
	/**
	 * stops the animated update timer
	 */
	public static void stopAnimation(){
		refreshTimer.stop();
	}
	
	/**
	 * ovveridden method for painting the panel
	 */
	public void paintComponent(Graphics g){
		//System.out.println(myN);
		if(antialiased)
			((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		super.paintComponent(g);
		
		int x = this.getWidth()/2;
		int y = this.getHeight()/2;
		
		float oneRadius = (float) (scale);//number of pixels corresponding to value 1
		
		g.setColor(lineColor);
		g.drawLine(x, 0, x, this.getHeight());
		g.drawLine(0, y, this.getWidth(), y);
		
		//int maxStep = (int) (getWidth()/scale);
		
		g.setColor(stringColor);
		int dim = ((int) scale);
		g.drawString("+1",x+dim, y);
		g.drawString("-1", x-dim, y);
		g.drawString("i", x, y-dim);
		g.drawString("-i", x, y+dim);
		g.setColor(lineColor);
		g.drawOval(x-dim, y-dim, 2*dim, 2*dim);
		/*for(int i = 0 ; i <= maxStep ; i++){
			int size =(int)(((float)i)*(scale));
			g.setColor(lineColor);
			g.drawOval(x-size, y-size, 2*size, 2*size);
		}*/
		
		g.setColor(vectorColor);
		float m = myN.magnitude().getReal();
		g.fillArc(
				x-(int)(oneRadius*m/4),
				y-(int)(oneRadius*m/4),
				(int)(oneRadius*m/2), (int)(oneRadius*m/2), 0,
				(int)(360*myN.phase().getReal()/(2*Math.PI)));
		
		myN.draw(g, x, y, scale);
		g.setColor(stringColor);
		g.drawString(myN.toString(), 10, 12);
		
	}
	
	
	public void mouseDragged(MouseEvent arg0) {
		if(arg0.isControlDown()){
			float previousDistFromCentre =
				(float) Math.hypot(pixToReal(mouseX,mouseY)[0],pixToReal(mouseX,mouseY)[1]);
			
			float distFromCentre = 
				(float) Math.hypot(pixToReal(arg0.getX(),arg0.getY())[0],pixToReal(arg0.getX(),arg0.getY())[1]);
			
			//float minimumScale = 0.05f;//any less will kill the program!
			//if((savedScale * (distFromCentre/previousDistFromCentre))>=minimumScale){
			scale = savedScale*(distFromCentre/previousDistFromCentre);
			/*}else{
				scale = minimumScale;
			}*/
			repaint();
		}else if(editable){
			float [] realCoords = pixToReal(arg0.getX(),arg0.getY());
			myN.setReal( realCoords[0] );
			myN.setImaginary( realCoords[1] );
			for(Frame f : JFrame.getFrames())f.repaint();//repaint all frames in program
		}
	}
	
	/**
	 * Update the recorded mouse coordinates
	 */
	public void mouseMoved(MouseEvent arg0) {mouseX = arg0.getX();mouseY = arg0.getY();}
	
	public void mouseClicked(MouseEvent arg0) {}
	
	public void mouseEntered(MouseEvent arg0) {}
	
	public void mouseExited(MouseEvent arg0) {}
	
	/**
	 * save the scale in use before the mouse was depressed
	 */
	public void mousePressed(MouseEvent arg0) {
		this.savedScale = scale;
	}
	public void mouseReleased(MouseEvent arg0) {
	}
	
	/**
	 * if the animation timer is in use, repaint the panel with every tick
	 */
	public void actionPerformed(ActionEvent arg0) {
		repaint();
	}
	
	
}
